package botTicTacToe;

import java.util.HashMap;

/** Not actually a tree, but provides tree-like interface
 * 
 * @author NP
 *
 */
public class GameTree {
	private GameField currentField;
	private HashMap<GameField, GameNode> nodeMap;
	
	public GameTree() {
		currentField = new GameField();
		nodeMap = new HashMap<GameField, GameNode>();
	}
	
	public GameTree(GameField field) {
		currentField = field;
		nodeMap = new HashMap<GameField, GameNode>();
	}
	
	public void turn(int mark, int x, int y) {
		currentField.placeMark(mark, x, y);
	}
	
	public void turn(int mark, int cellN) {
		currentField.placeMark(mark, cellN);
	}
	
	public GameNode getCurrentNode() {
		return getNode(currentField);
	}
	
	public GameNode getNode(GameField field) {
		return nodeMap.get(field);
	}
	
	public GameField getCurrentField() {
		return currentField;
	}
	
	public void generateMap(int nextTurn) {
		generateMap(currentField, nextTurn);
	}
	
	private void generateMap(GameField currentField, int nextTurn) {		
		GameNode node = new GameNode();
		if (currentField.isGameEnd()) {
			switch (currentField.getWinner()) {
			case 1:
				node.setWinsX(1);
				break;
			case 2:
				node.setWinsO(1);
				break;
			case 3:
				node.setDraws(1);
				break;
			}
			nodeMap.put(currentField, node);
			return;
		}
		
		int[] emptyCells = currentField.getEmptyCells();
		for (int cell: emptyCells) {
			GameField field = null;
			try {
				field = currentField.clone();
			} catch (CloneNotSupportedException e) {
				e.printStackTrace();
			}
			
			field.setMark(nextTurn, cell);
			if (!nodeMap.containsKey(field))
				generateMap(field, nextTurn == 1? 2 : 1);
			GameNode fieldNode = nodeMap.get(field);
			node.setWinsX(node.getWinsX() + fieldNode.getWinsX());
			node.setWinsO(node.getWinsO() + fieldNode.getWinsO());
			node.setDraws(node.getDraws() + fieldNode.getDraws());
		}
		nodeMap.put(currentField, node);
	}
	
	public static class GameNode {
		private int winsX;
		private int winsO;
		private int draws;

		public GameNode() {
			winsX = 0;
			winsO = 0;
			draws = 0;
		}
		
		/**
		 * @return the winsX
		 */
		public int getWinsX() {
			return winsX;
		}

		/**
		 * @return the winsO
		 */
		public int getWinsO() {
			return winsO;
		}
		
		/**
		 * @return the draws
		 */
		public int getDraws() {
			return draws;
		}
		
		public void setWinsX(int winsX) {
			this.winsX = winsX;
		}

		public void setWinsO(int winsO) {
			this.winsO = winsO;
		}

		public void setDraws(int draws) {
			this.draws = draws;
		}
	}
}
